if breakAgain,退出一层循环后,根据 breakAgain 变量判断是否需要再次退出外层循环。
fmt.Println("done"),退出所有循环后,打印 done。
将上面的代码使用Go语言的 goto 语句进行优化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
package main import"fmt" funcmain() { for x := 0; x < 10; x++ { for y := 0; y < 10; y++ { if y == 2 { // 跳转到标签 goto breakHere } } } // 手动返回, 避免执行进入标签 return // 标签 breakHere: fmt.Println("done") }
package main import ( "fmt" ) funcmain() { fmt.Printf("%T", nil) print(nil) } /* PS D:\code> go run .\main.go # command-line-arguments .\main.go:9:10: use of untyped nil */
不同类型 nil 的指针是一样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
package main import ( "fmt" ) funcmain() { var arr []int var num *int fmt.Printf("%p\n", arr) fmt.Printf("%p", num) } /* PS D:\code> go run .\main.go 0x0 0x0 */
通过运行结果可以看出 arr 和 num 的指针都是 0x0。
不同类型的 nil 是不能比较的
1 2 3 4 5 6 7 8 9 10 11 12 13 14
package main import ( "fmt" ) funcmain() { var m map[int]string var ptr *int fmt.Printf(m == ptr) } /* PS D:\code> go run .\main.go # command-line-arguments .\main.go:10:20: invalid operation: arr == ptr (mismatched types []int and *int) */
两个相同类型的 nil 值也可能无法比较
在Go语言中 map、slice 和 function 类型的 nil 值不能比较,比较两个无法比较类型的值是非法的,下面的语句无法编译。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
package main import ( "fmt" ) funcmain() { var s1 []int var s2 []int fmt.Printf(s1 == s2) } /* PS D:\code> go run .\main.go # command-line-arguments .\main.go:10:19: invalid operation: s1 == s2 (slice can only be compared to nil) */
通过上面的错误提示可以看出,能够将上述不可比较类型的空值直接与 nil 标识符进行比较,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12
package main import ( "fmt" ) funcmain() { var s1 []int fmt.Println(s1 == nil) } /* PS D:\code> go run .\main.go true */
package main import ( "fmt" ) funcmain() { var m map[int]string var ptr *int var c chanint var sl []int var f func() var i interface{} fmt.Printf("%#v\n", m) fmt.Printf("%#v\n", ptr) fmt.Printf("%#v\n", c) fmt.Printf("%#v\n", sl) fmt.Printf("%#v\n", f) fmt.Printf("%#v\n", i) } /* PS D:\code> go run .\main.go map[int]string(nil) (*int)(nil) (chan int)(nil) []int(nil) (func())(nil) <nil> */
package main import ( "fmt" "unsafe" ) funcmain() { var p *struct{} fmt.Println( unsafe.Sizeof( p ) ) // 8 var s []int fmt.Println( unsafe.Sizeof( s ) ) // 24 var m map[int]bool fmt.Println( unsafe.Sizeof( m ) ) // 8 var c chanstring fmt.Println( unsafe.Sizeof( c ) ) // 8 var f func() fmt.Println( unsafe.Sizeof( f ) ) // 8 var i interface{} fmt.Println( unsafe.Sizeof( i ) ) // 16 }
for t := 0.0; t < cycles*2*math.Pi; t += res { x := math.Sin(t) y := math.Sin(t*freq + phase) img.SetColorIndex( size+int(x*size+0.5), size+int(y*size+0.5), blackIndex, // 最后插入的逗号不会导致编译错误,这是Go编译器的一个特性 ) // 小括号另起一行缩进,和大括号的风格保存一致 }
上面代码中,在每次循环的开始会创建临时变量 t,然后在每次循环迭代中创建临时变量 x 和 y。临时变量 x、y 存放在栈中,随着函数执行结束(执行遇到最后一个}),释放其内存。
package main import ( "fmt" ) // 将NewInt定义为int类型 type NewInt int // 将int取一个别名叫IntAlias type IntAlias = int funcmain() { // 将a声明为NewInt类型 var a NewInt // 查看a的类型名 fmt.Printf("a type: %T\n", a) // 将a2声明为IntAlias类型 var a2 IntAlias // 查看a2的类型名 fmt.Printf("a2 type: %T\n", a2) }
/* a type: main.NewInt a2 type: int */
type NewInt int ,将 NewInt 定义为 int 类型,这是常见的定义类型的方法,通过 type 关键字的定义,NewInt 会形成一种新的类型,NewInt 本身依然具备 int 类型的特性。
type IntAlias = int,将 IntAlias 设置为 int 的一个别名,使用 IntAlias 与 int 等效。
var a NewInt,将 a 声明为 NewInt 类型,此时若打印,则 a 的值为 0。
fmt.Printf("a type: %T\n", a),使用%T格式化参数,打印变量 a 本身的类型。
var a2 IntAlias,将 a2 声明为 IntAlias 类型,此时打印 a2 的值为 0。
fmt.Printf("a2 type: %T\n", a2),打印 a2 变量的类型。
结果显示 a 的类型是 main.NewInt,表示 main 包下定义的 NewInt 类型,a2 类型是 int,IntAlias 类型只会在代码中存在,编译完成时,不会有 IntAlias 类型。